/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 *
 * http://www.gnu.org/copyleft/gpl.html
 */
package com.l2dot.gameserver.network.clientpackets;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.logging.Logger;

import com.l2dot.Base64;
import com.l2dot.Config;
import com.l2dot.L2DatabaseFactory;
import com.l2dot.gameserver.Announcements;
import com.l2dot.gameserver.GmListTable;
import com.l2dot.gameserver.Olympiad;
import com.l2dot.gameserver.SevenSigns;
import com.l2dot.gameserver.TaskPriority;
import com.l2dot.gameserver.communitybbs.Manager.RegionBBSManager;
import com.l2dot.gameserver.datatables.MapRegionTable;
import com.l2dot.gameserver.handler.AdminCommandHandler;
import com.l2dot.gameserver.instancemanager.ClanHallManager;
import com.l2dot.gameserver.instancemanager.CoupleManager;
import com.l2dot.gameserver.instancemanager.CrownManager;
import com.l2dot.gameserver.instancemanager.DimensionalRiftManager;
import com.l2dot.gameserver.instancemanager.PetitionManager;
import com.l2dot.gameserver.instancemanager.SiegeManager;
import com.l2dot.gameserver.model.L2Character;
import com.l2dot.gameserver.model.L2Clan;
import com.l2dot.gameserver.model.L2Effect;
import com.l2dot.gameserver.model.L2ItemInstance;
import com.l2dot.gameserver.model.L2World;
import com.l2dot.gameserver.model.actor.instance.L2PcInstance;
import com.l2dot.gameserver.model.entity.ClanHall;
import com.l2dot.gameserver.model.entity.Couple;
import com.l2dot.gameserver.model.entity.Hero;
import com.l2dot.gameserver.model.entity.L2Event;
import com.l2dot.gameserver.model.entity.Siege;
import com.l2dot.gameserver.model.entity.TvTEvent;
import com.l2dot.gameserver.model.quest.Quest;
import com.l2dot.gameserver.network.SystemMessageId;
import com.l2dot.gameserver.network.serverpackets.Die;
import com.l2dot.gameserver.network.serverpackets.EtcStatusUpdate;
import com.l2dot.gameserver.network.serverpackets.ExStorageMaxCount;
import com.l2dot.gameserver.network.serverpackets.FriendList;
import com.l2dot.gameserver.network.serverpackets.HennaInfo;
import com.l2dot.gameserver.network.serverpackets.ItemList;
import com.l2dot.gameserver.network.serverpackets.NpcHtmlMessage;
import com.l2dot.gameserver.network.serverpackets.PledgeShowMemberListAll;
import com.l2dot.gameserver.network.serverpackets.PledgeShowMemberListUpdate;
import com.l2dot.gameserver.network.serverpackets.PledgeSkillList;
import com.l2dot.gameserver.network.serverpackets.PledgeStatusChanged;
import com.l2dot.gameserver.network.serverpackets.QuestList;
import com.l2dot.gameserver.network.serverpackets.ShortCutInit;
import com.l2dot.gameserver.network.serverpackets.SignsSky;
import com.l2dot.gameserver.network.serverpackets.SystemMessage;
import com.l2dot.gameserver.network.serverpackets.UserInfo;
import com.l2dot.gameserver.util.FloodProtector;




/**
 * Enter World Packet Handler<p>
 * <p>
 * 0000: 03 <p>
 * packet format rev656 cbdddd
 * <p>
 *
 * @version $Revision: 1.16.2.1.2.7 $ $Date: 2005/03/29 23:15:33 $
 */
public class EnterWorld extends L2GameClientPacket
{
	private static final String _C__03_ENTERWORLD = "[C] 03 EnterWorld";
	private static Logger _log = Logger.getLogger(EnterWorld.class.getName());

	public TaskPriority getPriority() { return TaskPriority.PR_URGENT; }

	@Override
	protected void readImpl()
	{
		// this is just a trigger packet. it has no content
	}

	@Override
	protected void runImpl()
	{
		L2PcInstance activeChar = getClient().getActiveChar();

		if (activeChar == null)
		{
			_log.warning("EnterWorld failed! activeChar is null...");
			getClient().closeNow();
		    return;
		}

		// Register in flood protector
		FloodProtector.getInstance().registerNewPlayer(activeChar.getObjectId());

		if (L2World.getInstance().findObject(activeChar.getObjectId()) != null)
		{
			if(Config.DEBUG)
				_log.warning("User already exist in OID map! User "+activeChar.getName()+" is character clone");
			//activeChar.closeNetConnection();
		}

        if (activeChar.isGM())
        {
        	if (Config.GM_STARTUP_INVULNERABLE
        			&& (!Config.ALT_PRIVILEGES_ADMIN && activeChar.getAccessLevel() >= Config.GM_GODMODE
        			  || Config.ALT_PRIVILEGES_ADMIN && AdminCommandHandler.getInstance().checkPrivileges(activeChar, "admin_invul")))
        		activeChar.setIsInvul(true);

            if (Config.GM_STARTUP_INVISIBLE
                    && (!Config.ALT_PRIVILEGES_ADMIN && activeChar.getAccessLevel() >= Config.GM_GODMODE
                      || Config.ALT_PRIVILEGES_ADMIN && AdminCommandHandler.getInstance().checkPrivileges(activeChar, "admin_invisible")))
                activeChar.getAppearance().setInvisible();

            if (Config.GM_STARTUP_SILENCE
                    && (!Config.ALT_PRIVILEGES_ADMIN && activeChar.getAccessLevel() >= Config.GM_MENU
                      || Config.ALT_PRIVILEGES_ADMIN && AdminCommandHandler.getInstance().checkPrivileges(activeChar, "admin_silence")))
                activeChar.setMessageRefusal(true);

            if (Config.GM_STARTUP_AUTO_LIST
                    && (!Config.ALT_PRIVILEGES_ADMIN && activeChar.getAccessLevel() >= Config.GM_MENU
                      || Config.ALT_PRIVILEGES_ADMIN && AdminCommandHandler.getInstance().checkPrivileges(activeChar, "admin_gmliston")))
            	GmListTable.getInstance().addGm(activeChar, false);
            else
            	GmListTable.getInstance().addGm(activeChar, true);

            if (Config.GM_NAME_COLOR_ENABLED)
            {
                if (activeChar.getAccessLevel() >= 100)
                    activeChar.getAppearance().setNameColor(Config.ADMIN_NAME_COLOR);
                else if (activeChar.getAccessLevel() >= 75)
                    activeChar.getAppearance().setNameColor(Config.GM_NAME_COLOR);
            }
        }
    
        // Apply color settings to clan leader when entering 
     	if (activeChar.getClan() != null && activeChar.isClanLeader() && Config.CLAN_LEADER_COLOR_ENABLED && activeChar.getClan().getLevel() >= Config.CLAN_LEADER_COLOR_CLAN_LEVEL) 
     	{  
     		activeChar.getAppearance().setTitleColor(Config.CLAN_LEADER_COLOR); 
     	}                 
		Quest.playerEnter(activeChar);
		activeChar.sendPacket(new QuestList());
		
        if (Config.PLAYER_SPAWN_PROTECTION > 0)
            activeChar.setProtection(true);

        // restore info about chat ban
        activeChar.checkBanChat(false);

		// check for crowns
		CrownManager.getInstance().checkCrowns(activeChar);
		
		activeChar.spawnMe(activeChar.getX(), activeChar.getY(), activeChar.getZ());

		if (L2Event.active && L2Event.connectionLossData.containsKey(activeChar.getName()) && L2Event.isOnEvent(activeChar))
            L2Event.restoreChar(activeChar);
        else if (L2Event.connectionLossData.containsKey(activeChar.getName()))
            L2Event.restoreAndTeleChar(activeChar);
		if (SevenSigns.getInstance().isSealValidationPeriod())
			sendPacket(new SignsSky());

        // buff and status icons
		if (Config.STORE_SKILL_COOLTIME)
            activeChar.restoreEffects();

        activeChar.sendPacket(new EtcStatusUpdate(activeChar));

        // engage and notify Partner
        if(Config.L2JMOD_ALLOW_WEDDING)
        {
            engage(activeChar);
            notifyPartner(activeChar,activeChar.getPartnerId());
        }

        if (activeChar.getAllEffects() != null)
        {
            for (L2Effect e : activeChar.getAllEffects())
            {
                if (e.getEffectType() == L2Effect.EffectType.HEAL_OVER_TIME)
                {
                    activeChar.stopEffects(L2Effect.EffectType.HEAL_OVER_TIME);
                    activeChar.removeEffect(e);
                }

                if (e.getEffectType() == L2Effect.EffectType.COMBAT_POINT_HEAL_OVER_TIME)
                {
                    activeChar.stopEffects(L2Effect.EffectType.COMBAT_POINT_HEAL_OVER_TIME);
                    activeChar.removeEffect(e);
                }
            }
        }

        // apply augmentation boni for equipped items
        for (L2ItemInstance temp : activeChar.getInventory().getAugmentedItems())
        	if (temp != null && temp.isEquipped()) temp.getAugmentation().applyBoni(activeChar);

        //Expand Skill
        ExStorageMaxCount esmc = new ExStorageMaxCount(activeChar);
        activeChar.sendPacket(esmc);
        activeChar.getMacroses().sendUpdate();
        sendPacket(new UserInfo(activeChar));
        sendPacket(new HennaInfo(activeChar));
        sendPacket(new FriendList(activeChar));
        sendPacket(new ItemList(activeChar, false));        	
        sendPacket(new ShortCutInit(activeChar));
        SevenSigns.getInstance().sendCurrentPeriodMsg(activeChar);
        Announcements.getInstance().showAnnouncements(activeChar);
		Quest.playerEnter(activeChar);
		PetitionManager.getInstance().checkPetitionMessages(activeChar);

        // send user info again .. just like the real client
        //sendPacket(ui);

        if (activeChar.getClanId() != 0 && activeChar.getClan() != null)
        {
        	sendPacket(new PledgeShowMemberListAll(activeChar.getClan(), activeChar));
        	sendPacket(new PledgeStatusChanged(activeChar.getClan()));
        }

		if (activeChar.isAlikeDead())
		{
			// no broadcast needed since the player will already spawn dead to others
			sendPacket(new Die(activeChar));
		}

		if (Config.ALLOW_WATER)
		    activeChar.checkWaterState();

		if (Config.SHOW_HTML_WELCOME)
		{
			String Welcome_Path = "data/html/welcome.htm";
			File mainText = new File(Config.DATAPACK_ROOT, Welcome_Path); // Return the pathfile of the HTML file
			if (mainText.exists())
			{
				NpcHtmlMessage html = new NpcHtmlMessage(1);
				html.setFile(Welcome_Path);
				html.replace("%name%", activeChar.getName()); // replaces %name% with activeChar.getName(), so you can say like "welcome to the server %name%"
				sendPacket(html);
			}
		}
		
        if (Hero.getInstance().getHeroes() != null &&
                Hero.getInstance().getHeroes().containsKey(activeChar.getObjectId()))
            activeChar.setHero(true);

        setPledgeClass(activeChar);

		//add char to online characters
		activeChar.setOnlineStatus(true);

        notifyFriends(activeChar);
		notifyClanMembers(activeChar);
		notifySponsorOrApprentice(activeChar);

		activeChar.onPlayerEnter();

		if (Olympiad.getInstance().playerInStadia(activeChar))
        {
            activeChar.teleToLocation(MapRegionTable.TeleportWhereType.Town);
            activeChar.sendMessage("You have been teleported to the nearest town due to you being in an Olympiad Stadium");
        }

        if (DimensionalRiftManager.getInstance().checkIfInRiftZone(activeChar.getX(), activeChar.getY(), activeChar.getZ(), false))
        {
            DimensionalRiftManager.getInstance().teleportToWaitingRoom(activeChar);
        }
		if (activeChar.getClanJoinExpiryTime() > System.currentTimeMillis())
		{
			activeChar.sendPacket(new SystemMessage(SystemMessageId.CLAN_MEMBERSHIP_TERMINATED));
		}

		if (activeChar.getClan() != null)
		{
			activeChar.sendPacket(new PledgeSkillList(activeChar.getClan()));

			for (Siege siege : SiegeManager.getInstance().getSieges())
		    {
		    	if (!siege.getIsInProgress()) continue;
				if (siege.checkIsAttacker(activeChar.getClan()))
		    		activeChar.setSiegeState((byte)1);
				else if (siege.checkIsDefender(activeChar.getClan()))
		    		activeChar.setSiegeState((byte)2);
		    }
			// Add message at connexion if clanHall not paid.
			// Possibly this is custom...
			ClanHall clanHall = ClanHallManager.getInstance().getClanHallByOwner(activeChar.getClan());
			if(clanHall != null){
				if(!clanHall.getPaid()){
					activeChar.sendPacket(new SystemMessage(SystemMessageId.PAYMENT_FOR_YOUR_CLAN_HALL_HAS_NOT_BEEN_MADE_PLEASE_MAKE_PAYMENT_TO_YOUR_CLAN_WAREHOUSE_BY_S1_TOMORROW));
				}
			}
		}

		if (!activeChar.isGM() && activeChar.getSiegeState() < 2 && activeChar.isInsideZone(L2Character.ZONE_SIEGE))
		{
            // Attacker or spectator logging in to a siege zone. Actually should be checked for inside castle only?
			activeChar.teleToLocation(MapRegionTable.TeleportWhereType.Town);
            activeChar.sendMessage("You have been teleported to the nearest town due to you being in siege zone");
		}
		RegionBBSManager.getInstance().changeCommunityBoard();
        TvTEvent.onLogin(activeChar);
        }
         

    /**
     * @param activeChar
     */
    private void engage(L2PcInstance cha)
    {
        int _chaid = cha.getObjectId();

        for(Couple cl: CoupleManager.getInstance().getCouples())
        {
           if(cl.getPlayer1Id()==_chaid || cl.getPlayer2Id()==_chaid)
            {
                if(cl.getMaried())
                    cha.setMarried(true);

                cha.setCoupleId(cl.getId());

                if(cl.getPlayer1Id()==_chaid)
                {
                    cha.setPartnerId(cl.getPlayer2Id());
                }
                else
                {
                    cha.setPartnerId(cl.getPlayer1Id());
                }
            }
        }
    }

    /**
     * @param activeChar partnerid
     */
    private void notifyPartner(L2PcInstance cha,int partnerId)
    {
        if(cha.getPartnerId()!=0)
        {
            L2PcInstance partner;
            partner = (L2PcInstance)L2World.getInstance().findObject(cha.getPartnerId());

            if (partner != null)
            {
                partner.sendMessage("Your Partner has logged in");
            }

            partner = null;
        }
    }

	/**
	 * @param activeChar
	 */
	private void notifyFriends(L2PcInstance cha)
	{
		java.sql.Connection con = null;

		try {
		    con = L2DatabaseFactory.getInstance().getConnection();
		    PreparedStatement statement;
		    statement = con.prepareStatement("SELECT friend_name FROM character_friends WHERE char_id=?");
		    statement.setInt(1, cha.getObjectId());
		    ResultSet rset = statement.executeQuery();

		    L2PcInstance friend;
            String friendName;

            SystemMessage sm = new SystemMessage(SystemMessageId.FRIEND_S1_HAS_LOGGED_IN);
            sm.addString(cha.getName());

            while (rset.next())
            {
                friendName = rset.getString("friend_name");

                friend = L2World.getInstance().getPlayer(friendName);

                if (friend != null) //friend logged in.
                {
                	friend.sendPacket(new FriendList(friend));
                    friend.sendPacket(sm);
                }
		    }
            sm = null;

            rset.close();
            statement.close();
        }
		catch (Exception e) {
            _log.warning("could not restore friend data:"+e);
        }
		finally {
            try {con.close();} catch (Exception e){}
        }
	}

	/**
	 * @param activeChar
	 */
	private void notifyClanMembers(L2PcInstance activeChar)
	{
		L2Clan clan = activeChar.getClan();
		if (clan != null)
		{
			clan.getClanMember(activeChar.getName()).setPlayerInstance(activeChar);
			SystemMessage msg = new SystemMessage(SystemMessageId.CLAN_MEMBER_S1_LOGGED_IN);
			msg.addString(activeChar.getName());
			clan.broadcastToOtherOnlineMembers(msg, activeChar);
			msg = null;
			clan.broadcastToOtherOnlineMembers(new PledgeShowMemberListUpdate(activeChar), activeChar);
		}
	}

	/**
	 * @param activeChar
	 */
	private void notifySponsorOrApprentice(L2PcInstance activeChar)
	{
		if (activeChar.getSponsor() != 0)
		{
			L2PcInstance sponsor = (L2PcInstance)L2World.getInstance().findObject(activeChar.getSponsor());

			if (sponsor != null)
			{
				SystemMessage msg = new SystemMessage(SystemMessageId.YOUR_APPRENTICE_S1_HAS_LOGGED_IN);
				msg.addString(activeChar.getName());
				sponsor.sendPacket(msg);
			}
		}
		else if (activeChar.getApprentice() != 0)
		{
			L2PcInstance apprentice = (L2PcInstance)L2World.getInstance().findObject(activeChar.getApprentice());

			if (apprentice != null)
			{
				SystemMessage msg = new SystemMessage(SystemMessageId.YOUR_SPONSOR_S1_HAS_LOGGED_IN);
				msg.addString(activeChar.getName());
				apprentice.sendPacket(msg);
			}
		}
	}

	/**
	 * @param string
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	@SuppressWarnings("unused")
	private String getText(String string)
	{
		try {
			String result = new String(Base64.decode(string), "UTF-8");
			return result;
		} catch (UnsupportedEncodingException e) {
			// huh, UTF-8 is not supported? :)
			return null;
		}
	}
	

    /* (non-Javadoc)
	 * @see com.l2dot.gameserver.clientpackets.ClientBasePacket#getType()
	 */
	@Override
	public String getType()
	{
		return _C__03_ENTERWORLD;
	}

	private void setPledgeClass(L2PcInstance activeChar)
	{
		int pledgeClass = 0;
		if ( activeChar.getClan() != null)
			pledgeClass = activeChar.getClan().getClanMember(activeChar.getObjectId()).calculatePledgeClass(activeChar);

		if (activeChar.isNoble() && pledgeClass < 5)
	           pledgeClass = 5;

	    if (activeChar.isHero())
	           pledgeClass = 8;

	    activeChar.setPledgeClass(pledgeClass);
	}
}
